#include "stdafx.h"
#include "LookAtCamera.h"
#include "Globals.h"


//Globals Variable
Matrix maRotation;
GLfloat fDeltaRot = 0;

void LookAtCamera::UpdateNewTargetRotation()
{
	CalculateWVMatrix();
	//Calculation Rotation
	Vector4 vTargetL = Vector4(0.0f, 0.0f, -(m_vPosition - m_vTarget).Length(), 1.0f);
	Vector4 vTargetNewL = vTargetL * maRotation;
	Vector4 vTargetNewW = vTargetNewL * m_maWorld;
	m_vTarget = Vector3(vTargetNewW.x, vTargetNewW.y, vTargetNewW.z);
}

void LookAtCamera::UpdateNewPosition()
{
	CalculateWVMatrix();
	//Calculate Translation
	Vector3 deltaMoveZ = (m_vPosition - m_vTarget).Normalize();
	Vector3 deltaMoveX = (m_vUp.Cross(deltaMoveZ)).Normalize();		Vector3 deltaMoveY = (deltaMoveZ.Cross(deltaMoveX)).Normalize();
	if(m_fOffsetX != 0)
	{
		deltaMoveX *= m_fOffsetX;
		m_vPosition += deltaMoveX;
		m_vTarget += deltaMoveX;
	}
	if(m_fOffsetY != 0)
	{
		deltaMoveY *= m_fOffsetY;
		m_vPosition += deltaMoveY;
		m_vTarget += deltaMoveY;
	}
	if(m_fOffsetZ != 0)
	{
		deltaMoveZ *= m_fOffsetZ;
		m_vPosition += deltaMoveZ;
		m_vTarget += deltaMoveZ;
	}
	m_fOffsetX = 0.0f;
	m_fOffsetY = 0.0f;
	m_fOffsetZ = 0.0f;
	m_bIsChanged = false;
}

LookAtCamera::LookAtCamera()
{
	m_vPosition = Vector3(0.0f, 0.0f, 15.0f);
	m_vUp = Vector3(0.0f, 1.0f, 0.0f);
	m_fOffsetX = 0.0f;
	m_fOffsetY = 0.0f;
	m_fOffsetZ = 0.0f;
	m_fRotX = 0.0f;
	m_fRotY = 0.0f;
	m_fRotZ = 0.0f;

	m_maView.SetIdentity();
	m_maWorld.SetIdentity();

	m_bIsChanged = false;

	CalculateWVMatrix();
}

void LookAtCamera::CalculateWVMatrix()
{
	Matrix maRot, maTran;
	maRot.SetIdentity();
	maTran.SetIdentity();

	//Calculate World
	Vector3 zaxis = (m_vPosition - m_vTarget).Normalize();
	Vector3 xaxis = (m_vUp.Cross(zaxis)).Normalize();
	Vector3 yaxis = (zaxis.Cross(xaxis)).Normalize();
	maRot.m[0][0] = xaxis.x;	maRot.m[0][1] = xaxis.y;	maRot.m[0][2] = xaxis.z;	maRot.m[0][3] = 0.0f;
	maRot.m[1][0] = yaxis.x;	maRot.m[1][1] = yaxis.y;	maRot.m[1][2] = yaxis.z;	maRot.m[1][3] = 0.0f;
	maRot.m[2][0] = zaxis.x;	maRot.m[2][1] = zaxis.y;	maRot.m[2][2] = zaxis.z;	maRot.m[2][3] = 0.0f;
	maRot.m[3][0] = 0.0f;		maRot.m[3][1] = 0.0f;		maRot.m[3][2] = 0.0f;		maRot.m[3][3] = 1.0f;

	maTran.m[3][0] = m_vPosition.x;
	maTran.m[3][1] = m_vPosition.y;
	maTran.m[3][2] = m_vPosition.z;

	//World matrix
	m_maWorld = maRot * maTran;

	//Calculate View
	maRot = maRot.Transpose();

	maTran.m[3][0] *= -1.0f;
	maTran.m[3][1] *= -1.0f;
	maTran.m[3][2] *= -1.0f;

	//View matrix
	m_maView = maTran * maRot;
}

Matrix LookAtCamera::GetWorldMatrix()
{
	return m_maWorld;
}

Matrix LookAtCamera::GetViewMatrix()
{
	return m_maView;
}

void LookAtCamera::Update(ESContext *esContext, GLfloat deltaTime)
{
	if(m_bIsChanged)
	{
		UpdateNewTargetRotation();
		UpdateNewPosition();
		m_bIsChanged = false;
	}
}

void LookAtCamera::MoveLeft(GLfloat offset)
{
	m_bIsChanged = true;
	m_fOffsetX = -offset;
}

void LookAtCamera::MoveRight(GLfloat offset)
{
	m_bIsChanged = true;
	m_fOffsetX = offset;
}

void LookAtCamera::MoveDown(GLfloat offset)
{
	m_bIsChanged = true;
	m_fOffsetY = -offset;
}

void LookAtCamera::MoveUp(GLfloat offset)
{
	m_bIsChanged = true;
	m_fOffsetY = offset;
}

void LookAtCamera::MoveBackward(GLfloat offset)
{
	m_bIsChanged = true;
	m_fOffsetZ = -offset;
}

void LookAtCamera::MoveForward(GLfloat offset)
{
	m_bIsChanged = true;
	m_fOffsetZ = offset;
}

void LookAtCamera::RotateLeft(GLfloat offset)
{
	m_bIsChanged = true;
	m_fRotY = -offset;
	maRotation.SetIdentity().SetRotationY(m_fRotY);
}

void LookAtCamera::RotateRight(GLfloat offset)
{
	m_bIsChanged = true;
	m_fRotY = offset;
	maRotation.SetIdentity().SetRotationY(m_fRotY);
}


void LookAtCamera::RotateDown(GLfloat offset)
{
	if(fDeltaRot <= -3.14/4.0f)
	{
		m_bIsChanged = false;
		offset = 0;
	}
	else
	{
		m_bIsChanged = true;
		m_fRotX = -offset;
		maRotation.SetIdentity().SetRotationX(m_fRotX);
		fDeltaRot += m_fRotX;
	}
}

void LookAtCamera::RotateUp(GLfloat offset)
{
	if(fDeltaRot >= 3.14/4.0f)
	{
		m_bIsChanged = false;
		offset = 0;
	}
	else
	{
		m_bIsChanged = true;
		m_fRotX = offset;
		maRotation.SetIdentity().SetRotationX(m_fRotX);
		fDeltaRot += m_fRotX;
	}
}